#include "stdafx.h"
#include "Window.h"

using namespace MomogenkyouSystem;

HINSTANCE	Window::m_hInstance(NULL);
HWND		Window::m_hWnd(NULL);
RECT		Window::m_WndRect;
WNDCLASSEX	Window::m_WCEX;

bool		Window::m_bExitProgram(false);
float		Window::m_fInterval(0);
float		Window::m_fPrevInterval(0);
size_t		Window::m_iFrameRate(0);

std::deque<void (*)(const float &)>	Window::m_Callbacks;

LRESULT	CALLBACK Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	UnicodeText::WndProc(hWnd, uMsg, wParam, lParam);
	switch(uMsg)
	{
	case WM_MOVE:
		break;

	case WM_DESTROY:
	case WM_QUIT:
		m_bExitProgram = true;
		break;

	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}

bool	Window::Initialize(HINSTANCE hInstance, size_t Width, size_t Height)
{
	m_hInstance = hInstance;

	m_WndRect.top		= (GetSystemMetrics(SM_CYSCREEN) >> 1) - (Height >> 1);
	m_WndRect.left		= (GetSystemMetrics(SM_CXSCREEN) >> 1) - (Width	>> 1);
	m_WndRect.right		= Width		+ APP_BORDER_OFFSET_WIDTH;
	m_WndRect.bottom	= Height	+ APP_BORDER_OFFSET_HEIGHT;

	m_WCEX.cbSize = sizeof(WNDCLASSEX);

	m_WCEX.style			= CS_HREDRAW | CS_VREDRAW;
	m_WCEX.lpfnWndProc		= (WNDPROC)MomogenkyouSystem::Window::WndProc;
	m_WCEX.cbClsExtra		= 0;
	m_WCEX.cbWndExtra		= 0;
	m_WCEX.hInstance		= m_hInstance;
	m_WCEX.hIcon			= LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MOMOGENKYOU));
	m_WCEX.hCursor			= LoadCursor(NULL, IDC_ARROW);
	m_WCEX.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	m_WCEX.lpszMenuName		= NULL;
	m_WCEX.lpszClassName	= APP_CLASS;
	m_WCEX.hIconSm			= LoadIcon(m_WCEX.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	ATOM Registeration = RegisterClassEx(&m_WCEX);
	ASSERT(Registeration, "Failed To Register class");

	m_hWnd	=	CreateWindowEx(	WS_EX_APPWINDOW, 
								APP_CLASS, 
								APP_TITLE, 
								WS_BORDER | WS_SYSMENU, 
								m_WndRect.left, m_WndRect.top,
								m_WndRect.right, m_WndRect.bottom, 
								NULL, NULL, m_hInstance, NULL);

	ShowWindow(m_hWnd, 1);
	UpdateWindow(m_hWnd);

	WriteCommandLine("> Window >> Initialized");
	return	true;
}

bool	Window::Shutdown()
{
	m_Callbacks.clear();
	CloseWindow(m_hWnd);
	m_hWnd		=	NULL;
	m_hInstance	=	NULL;

	WriteCommandLine("> Window >> Shutdown");
	return	true;
}

void	Window::AddCallBack(void * pCallBack)
{
	m_Callbacks.push_back((void (*)(const float &))pCallBack);
}

int		Window::RunProgram()
{
	WriteCommandLine("Window > Run Program");
	MSG		_MSG;

	System_HiResTimer	_Timer;
	float				_ElapsedTime(0);
	float				_TimeDifference(0);
	float				_ClockRate(1.0f / 60.0f);
	
	size_t				_FrameCount(0);

	while(!m_bExitProgram)
	{
		if(PeekMessage(&_MSG, m_hWnd, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&_MSG);
			DispatchMessage(&_MSG);
			continue;
		}
		m_fPrevInterval = m_fInterval;

		_Timer.Start();

		//	Update etc
		for(size_t i = 0; i < m_Callbacks.size(); i++)
			m_Callbacks[i](m_fPrevInterval);

		//	FrameRate stuff
		m_fInterval		=	_Timer.End()	*	0.001f;
		_TimeDifference	=	_ClockRate	-	m_fInterval;

		//	Sleep if the loop is too fast
		if(_TimeDifference > 0)
			Sleep(static_cast<DWORD>(_TimeDifference * 1000));

		_TimeDifference	=	max(0.0f, _TimeDifference);

		_ElapsedTime	+=	_TimeDifference	+	m_fInterval;
		m_fInterval		+=	_TimeDifference;

		_FrameCount++;

		if(_ElapsedTime > 1.0f)
		{
			m_iFrameRate	=	_FrameCount;
			_ElapsedTime	=	0;
			_FrameCount		=	0;
#ifndef	DEPLOY
			SetWindowTextA(m_hWnd, FORMATTEXT("FPS %i Interval : %f", m_iFrameRate, m_fInterval).c_str());
#endif
		}
	}
	return	0;
}